package org.micode.common.utils;

import lombok.Cleanup;
import org.micode.common.codec.SnowflakeCodec;
import org.springframework.web.multipart.MultipartFile;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.Objects;

public class MultipartFileUtils {

    private final static int ERROR_INDEX = -1;

    public final static String POINT = ".";
    public final static String PATH_SEP = "/";

    public static String saveTo(MultipartFile multipartFile,
                                String targetFile) throws IOException {
        return innerSaveTo(multipartFile, targetFile);
    }

    public static String save(MultipartFile multipartFile,
                              String documentDir,
                              String documentUrlPrefix) throws IOException {
        return save(multipartFile, null, null, documentDir, documentUrlPrefix);
    }

    public synchronized static String save(MultipartFile multipartFile,
                                           String filePreName,
                                           String extName,
                                           String documentDir,
                                           String documentUrlPrefix) throws IOException {
        if (StringExtUtils.isAnyEmpty(extName)) {
            extName = Objects.requireNonNull(multipartFile.getOriginalFilename())
                    .substring(multipartFile.getOriginalFilename().lastIndexOf(POINT) + 1);
        }
        if (StringExtUtils.isAnyEmpty(extName)) {
            extName = "tmp";
        }

        final String theName;
        if (!StringExtUtils.isAnyEmpty(filePreName)) {
            theName = filePreName + "_" + SnowflakeCodec.defaultNextId() + POINT + extName;
        } else {
            theName = SnowflakeCodec.defaultNextId() + POINT + extName;
        }

        String theFileName = innerSaveTo(multipartFile, FileExtUtils.fullFilename(documentDir, theName));
        return documentUrlPrefix + theFileName;
    }

    private static String innerSaveTo(MultipartFile multipartFile, String targetFilename) throws IOException {
        final File targetFile = new File(targetFilename);
        if (!targetFile.getParentFile().exists()) {
            targetFile.getParentFile().mkdirs();
        }
        targetFile.deleteOnExit();
        targetFile.createNewFile();

        @Cleanup InputStream inputStream = multipartFile.getInputStream();
        @Cleanup FileOutputStream fileOutputStream = new FileOutputStream(targetFile);
        final BufferedInputStream bis = new BufferedInputStream(inputStream);
        final BufferedOutputStream bos = new BufferedOutputStream(fileOutputStream);

        int len;
        while ((len = bis.read()) != ERROR_INDEX) {
            bos.write(len);
            bos.flush();
        }

        return targetFile.getName();
    }

    public static String readText(MultipartFile multipartFile) throws IOException {
        return readText(multipartFile, "utf-8");
    }

    public static String readText(MultipartFile multipartFile, String charCodeName) throws IOException {
        InputStream in =  multipartFile.getInputStream();
        try (Reader reader = new InputStreamReader(in, charCodeName)) {
            int ch = 0;
            StringBuilder stringBuffer = new StringBuilder();
            while ((ch = reader.read()) != -1) {
                stringBuffer.append((char) ch);
            }
            return stringBuffer.toString();
        }
    }

    public static Boolean delete(String fileName, String documentDir) {
        File file = new File(documentDir, fileName);
        return file.delete();
    }

    public static void main(String[] args) {
        String path = "/topology/thumb.png";
        int pos = path.lastIndexOf(POINT);
        String extName = path.substring(pos + 1);
        String preName = path.substring(0, pos);
        System.out.println(extName);
        System.out.println(preName);
    }
}
